package com.mhy.crash.utils;


import android.content.Context;
import android.graphics.Bitmap;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;


public class HttpUtils {
    private HttpUtils() {
    }

    private static HttpUtils httpUtils;

    public static HttpUtils getInstance() {
        if (httpUtils == null) {
            synchronized (HttpUtils.class) {
                if (httpUtils == null) {
                    httpUtils = new HttpUtils();
                }
            }
        }
        return httpUtils;
    }

    private ExecutorService executorService = Executors.newCachedThreadPool();

    //使用ConnectivityManager检查网络状态步骤
    public boolean checkNetworkState(Context context) {
        ConnectivityManager connectivityManager = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        //1.通过系统服务获取ConnectivityManager类的对象
        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
        //2.调用getActiveNetworkInfo()获取当前活动的网络NetworkInfo对象
        if (networkInfo == null || networkInfo.isConnected() == false) {
            //3.判断当前网络状态是否为连接状态，如果当前没有网络是活动的，则返回null
            return false;
        } else {
            return true;
        }
    }

    private HttpCallback<String> httpCallback;

    public interface HttpCallback<T> {
        void onFinish(T response);     //成功响应

        void onError(Exception e);      //失败响应
    }

    final Handler handler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            if (httpCallback == null) {
                return;
            }
            //通过msg中传递数据判断是否登录成功，若成功则实现界面跳转到WelcomeActivity
            switch (msg.what) {
                case 0:
                    httpCallback.onFinish((String) msg.obj);
                    break;
                case 1:
                default:
                    httpCallback.onError((Exception) msg.obj);
                    break;
            }
        }
    };

    public void get(final String mUrl, Map<String, String> paramMap, final HttpCallback<String> listener) {
        httpCallback = listener;
        Runnable runnable = () -> {
            InputStream inputStream = null;
            HttpURLConnection urlConnection = null;
            String urlWithParams = formatUrlWithParas(mUrl, paramMap);
            try {
                // read responseURLEncoder.encode(para, "GBK");
                URL url = new URL(urlWithParams);
                urlConnection = (HttpURLConnection) url.openConnection();

                /* optional request header */
                urlConnection.setRequestProperty("Accept", "*/*");
                // 设置字符编码
                urlConnection.setRequestProperty("Charset", "UTF-8");
                /* for Get request */
                urlConnection.setRequestMethod("GET");
                int statusCode = urlConnection.getResponseCode();
                /* 200 represents HTTP OK */
                if (statusCode == HttpURLConnection.HTTP_OK) {
                    inputStream = new BufferedInputStream(urlConnection.getInputStream());
                    readInputStream(inputStream);
                }
            } catch (Exception e) {
                e.printStackTrace();
                resultError(e);
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (urlConnection != null) {
                    urlConnection.disconnect();
                }
            }
        };
        executorService.execute(runnable);
    }

   /* Map<String, String> map = new HashMap<>();
                    map.put("page","0");
                    map.put("num","10");
                    HttpUtils.getInstance().

    get("https://a1000.top/kaiche/gettest.php",map, httpCallback);
                    HttpUtils.getInstance().

    post("https://a1000.top/kaiche/posttest.php",map, httpCallback);*/

    public void post(String url, Map<String, String> paramMap, final HttpCallback<String> listener) {
        httpCallback = listener;
        Runnable runnable = () -> {
            InputStream inputStream = null;
            HttpURLConnection urlConnection = null;
            String params = joinParas(paramMap);
            try {
                URL mUrl = new URL(url);
                urlConnection = (HttpURLConnection) mUrl.openConnection();
                /* optional request header */
                //设置请求头数据提交方式，这里以form表单形式提交
                urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
                urlConnection.setRequestProperty("Accept", "application/json");
                // read response
                urlConnection.setRequestMethod("POST");
                urlConnection.setDoInput(true);
                urlConnection.setDoOutput(true);
                urlConnection.setUseCaches(false);
                urlConnection.setConnectTimeout(5000);
                DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream());
                wr.writeBytes(params);
                wr.flush();
                wr.close();
                // try to get response
                int statusCode = urlConnection.getResponseCode();
                if (statusCode == HttpURLConnection.HTTP_OK) {
                    inputStream = new BufferedInputStream(urlConnection.getInputStream());
                    readInputStream(inputStream);
                }
            } catch (Exception e) {
                e.printStackTrace();
                resultError(e);
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (urlConnection != null) {
                    urlConnection.disconnect();
                }
            }

        };
        executorService.execute(runnable);
    }

    public void postJson(String mUrl, String json, HttpCallback<String> httpCallback) {
        this.httpCallback = httpCallback;
        Runnable runnable = () -> {
            try {
                URL url = new URL(mUrl);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("POST");
                conn.setRequestProperty("Connection", "keep-Alive");
                conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
                conn.setRequestProperty("Accept", "application/json, text/plain, */*");
                //.setRequestProperty("Content-Length", data.length() + "");//设置请求头，设置提交数据的长度
                conn.setDoOutput(true);
                conn.setDoInput(true);
                conn.setUseCaches(false);
                conn.setConnectTimeout(5000);
                conn.connect();
                //Log.e("HTTP", "json = " + json);
                OutputStream os = conn.getOutputStream();
                os.write(json.getBytes("UTF-8"));
                os.flush();
                os.close();
                int responseCode = conn.getResponseCode();
                Log.e("HTTP", "responseCode = " + responseCode);
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    InputStream input = conn.getInputStream();
                    StringBuilder sb = new StringBuilder();
                    int ss;
                    while ((ss = input.read()) != -1) {
                        sb.append((char) ss);
                    }
                    resultSuccess(sb.toString());
                    Log.e("HTTP", "请求结果 = " + sb.toString());
                    input.close();
                }
                conn.disconnect();
            } catch (Exception e) {
                resultError(e);
                Log.e("HTTP", "出现异常: " + e.toString());
                e.printStackTrace();
            }
        };
        executorService.execute(runnable);
    }

    public void downloadFile(String url, String outDirPath) {
        Runnable futureTask = () -> {
            try {
                //下载路径，如果路径无效了，可换成你的下载路径
                final long startTime = System.currentTimeMillis();
                Log.i("DOWNLOAD", "startTime=" + startTime);
                //下载函数
                String filename = url.substring(url.lastIndexOf("/") + 1);
                //获取文件名
                URL myURL = new URL(url);
                URLConnection conn = myURL.openConnection();
                conn.connect();
                InputStream is = conn.getInputStream();
                int fileSize = conn.getContentLength();//根据响应获取文件大小
                if (fileSize <= 0) throw new RuntimeException("无法获知文件大小 ");
                if (is == null) throw new RuntimeException("stream is null");
                File file1 = new File(outDirPath);
                if (!file1.exists()) {
                    file1.mkdirs();
                }
                //把数据存入路径+文件名
                FileOutputStream fos = new FileOutputStream(outDirPath + "/" + filename);
                byte buf[] = new byte[1024];
                int downLoadFileSize = 0;
                do {
                    //循环读取
                    int numread = is.read(buf);
                    if (numread == -1) {
                        break;
                    }
                    fos.write(buf, 0, numread);
                    downLoadFileSize += numread;
                    //更新进度条
                } while (true);

                Log.i("DOWNLOAD", "download success");
                Log.i("DOWNLOAD", "totalTime=" + (System.currentTimeMillis() - startTime));

                is.close();
            } catch (Exception ex) {
                Log.e("DOWNLOAD", "error: " + ex.getMessage(), ex);
            }
        };
        executorService.execute(futureTask);
    }

    public String doPostWithFile(String url, String savefileName, String fileName, String param) {
        String result = "";
        FutureTask<String> futureTask = new FutureTask<>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                try {
                    // 换行符
                    final String newLine = "\r\n";
                    final String boundaryPrefix = "--";
                    // 定义数据分隔线
                    String BOUNDARY = "========7d4a6d158c9";
                    // 服务器的域名
                    URL realurl = new URL(url);
                    // 发送POST请求必须设置如下两行
                    HttpURLConnection connection = (HttpURLConnection) realurl.openConnection();
                    connection.setDoOutput(true);
                    connection.setDoInput(true);
                    connection.setUseCaches(false);
                    connection.setRequestMethod("POST");
                    connection.setRequestProperty("Connection", "Keep-Alive");
                    connection.setRequestProperty("Charset", "UTF-8");
                    connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
                    // 头
                    String boundary = BOUNDARY;
                    // 传输内容
                    StringBuffer contentBody = new StringBuffer("--" + BOUNDARY);
                    // 尾
                    String endBoundary = "\r\n--" + boundary + "--\r\n";
                    //输出
                    OutputStream out = connection.getOutputStream();
                    // 1. 处理普通表单域(即形如key = value对)的POST请求（这里也可以循环处理多个字段，或直接给json）
                    //这里看过其他的资料，都没有尝试成功是因为下面多给了个Content-Type
                    //form-data  这个是form上传 可以模拟任何类型
                    contentBody.append("\r\n")
                            .append("Content-Disposition: form-data; name=\"")
                            .append("param" + "\"")
                            .append("\r\n")
                            .append("\r\n")
                            .append(param)
                            .append("\r\n")
                            .append("--")
                            .append(boundary);
                    String boundaryMessage1 = contentBody.toString();
                    System.out.println(boundaryMessage1);
                    out.write(boundaryMessage1.getBytes(Charset.forName("UTF-8")));

                    // 2. 处理file文件的POST请求（多个file可以循环处理）
                    contentBody = new StringBuffer();
                    contentBody.append("\r\n")
                            .append("Content-Disposition:form-data; name=\"")
                            .append("file" + "\"; ")   // form中field的名称
                            .append("filename=\"")
                            .append(fileName + "\"")   //上传文件的文件名，包括目录
                            .append("\r\n")
                            .append("Content-Type:multipart/form-data")
                            .append("\r\n\r\n");
                    String boundaryMessage2 = contentBody.toString();
                    System.out.println(boundaryMessage2);
                    out.write(boundaryMessage2.getBytes("utf-8"));

                    // 开始真正向服务器写文件
                    File file = new File(savefileName);
                    DataInputStream dis = new DataInputStream(new FileInputStream(file));
                    int bytes = 0;
                    byte[] bufferOut = new byte[(int) file.length()];
                    bytes = dis.read(bufferOut);
                    out.write(bufferOut, 0, bytes);
                    dis.close();
                    byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
                    out.write(endData);
                    out.flush();
                    out.close();

                    // 4. 从服务器获得回答的内容
                    String strLine = "";
                    String strResponse = "";
                    InputStream in = connection.getInputStream();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                    while ((strLine = reader.readLine()) != null) {
                        strResponse += strLine + "\n";
                    }
                    System.out.print(strResponse);
                    return strResponse;
                } catch (Exception e) {
                    System.out.println("发送POST请求出现异常！" + e);
                    e.printStackTrace();
                    return "";
                }
            }
        });
        executorService.submit(futureTask);
        try {
            result = futureTask.get();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return result;
    }

    //将位图转换为字节缓冲：
    public byte[] bitMap2Byte(Bitmap bitmap) {
        //I want to send only 8 bit black & white bitmaps
        byte[] pixels = new byte[bitmap.getWidth() * bitmap.getHeight()];
        for (int i = 0; i < bitmap.getWidth(); ++i) {
            for (int j = 0; j < bitmap.getHeight(); ++j) {
                //we're interested only in the MSB of the first byte,
                //since the other 3 bytes are identical for B&W images
                pixels[i + j] = (byte) ((bitmap.getPixel(i, j) & 0x80) >> 7);
            }
        }
        return pixels;
    }


    private void resultError(Exception e) {
        Message msg = new Message();
        msg.what = 1;
        msg.obj = e;
        handler.sendMessage(msg);
    }

    private void resultSuccess(String result) {
        Message msg = new Message();
        msg.obj = result;
        msg.what = 0;
        handler.sendMessage(msg);
    }

    private void readInputStream(InputStream inputStream) throws IOException {
//        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
        String line = bufferedReader.readLine();
        StringBuilder builder = new StringBuilder();
        while (line != null) {
            builder.append(line);
            line = bufferedReader.readLine();
        }
        String result = builder.toString();
        resultSuccess(result);
    }


    /**
     * 将K-V的参数转为k=v&k=v的形式
     *
     * @param paramMap
     * @return
     */
    public String joinParas(Map<String, String> paramMap) {
        if (paramMap == null || paramMap.size() == 0) {
            return "";
        }
        StringBuilder paras = new StringBuilder();
        Iterator<Map.Entry<String, String>> ite = paramMap.entrySet().iterator();
        while (ite.hasNext()) {
            Map.Entry<String, String> entry = ite.next();
            paras.append(entry.getKey()).append("=").append(utf8Encode(entry.getValue()));
            if (ite.hasNext()) {
                paras.append("&");
            }
        }
        return paras.toString();
    }

    /**
     * 将请求的内容转为 url?a=b&i=j&c=d
     *
     * @param url      请求的前缀
     * @param paramMap 请求的参数
     * @return
     */
    public String formatUrlWithParas(String url, Map<String, String> paramMap) {
        StringBuilder urlWithParas = new StringBuilder(isEmpty(url) ? "" : url);
        String paras = joinParas(paramMap);
        if (!isEmpty(paras)) {
            urlWithParas.append("?").append(paras);
        }
        return urlWithParas.toString();
    }


    /**
     * 是否为空的判断
     *
     * @param str
     * @return
     */
    private boolean isEmpty(CharSequence str) {
        return (null == str || str.length() == 0);
    }

    /**
     * 将字符串进行UTF-8编码
     *
     * @param str
     * @return
     */
    private String utf8Encode(String str) {
        if (!isEmpty(str) && str.getBytes().length != str.length()) {
            try {
                return URLEncoder.encode(str, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                return str;
            }
        }
        return str;
    }


    public String getRequset(final String url) {
        final StringBuilder sb = new StringBuilder();
        FutureTask<String> task = new FutureTask<String>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                HttpURLConnection connection = null;
                BufferedReader reader = null;
                try {
                    URL requestUrl = new URL(url);
                    connection = (HttpURLConnection) requestUrl.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(8000);
                    connection.setReadTimeout(8000);
                    if (connection.getResponseCode() == 200) {
                        InputStream in = connection.getInputStream();
                        reader = new BufferedReader(new InputStreamReader(in));
                        String line;
                        while ((line = reader.readLine()) != null) {
                            sb.append(line);
                        }
                        System.out.println(sb);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (reader != null) {
                        reader.close();
                    }
                    if (connection != null) {
                        connection.disconnect();//断开连接，释放资源
                    }
                }
                return sb.toString();
            }
        });
//        new Thread(task).start();
        executorService.submit(task);
        String s = null;
        try {
            s = task.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return s;
    }

    public String postRequset(final String url, final Map<String, String> map) {
        final StringBuilder sb = new StringBuilder();
        FutureTask<String> task = new FutureTask<String>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                HttpURLConnection connection = null;
                BufferedReader reader = null;
                try {
                    URL requestUrl = new URL(url);
                    connection = (HttpURLConnection) requestUrl.openConnection();
                    connection.setRequestMethod("POST");
                    connection.setConnectTimeout(8000);//链接超时
                    connection.setReadTimeout(8000);//读取超时
                    //发送post请求必须设置
                    connection.setDoOutput(true);
                    connection.setDoInput(true);
                    connection.setUseCaches(false);
                    connection.setInstanceFollowRedirects(true);
                    connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
                    DataOutputStream out = new DataOutputStream(connection
                            .getOutputStream());
                    StringBuilder request = new StringBuilder();
                    for (String key : map.keySet()) {
                        request.append(key + "=" + URLEncoder.encode(map.get(key), "UTF-8") + "&");
                    }
                    out.writeBytes(request.toString());//写入请求参数
                    out.flush();
                    out.close();
                    if (connection.getResponseCode() == 200) {
                        InputStream in = connection.getInputStream();
                        reader = new BufferedReader(new InputStreamReader(in));
                        String line;
                        while ((line = reader.readLine()) != null) {
                            sb.append(line);
                        }
                        System.out.println(sb);

                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (reader != null) {
                        reader.close();//关闭流
                    }
                    if (connection != null) {
                        connection.disconnect();//断开连接，释放资源
                    }
                }
                return sb.toString();
            }
        });
//        new Thread(task).start();
        executorService.submit(task);
        String s = null;
        try {
            s = task.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return s;
    }

    /**
     * multipart/form-data类型的form提交
     * Java原生的API可用于发送HTTP请求，即java.net.URL、java.net.URLConnection，这些API很好用、很常用，
     * 但不够简便；
     * <p>
     * 1.通过统一资源定位器（java.net.URL）获取连接器（java.net.URLConnection） 2.设置请求的参数 3.发送请求
     * 4.以输入流的形式获取返回内容 5.关闭输入流
     * <p>
     * 多文件上传的方法
     *
     * @param actionUrl：上传的路径
     * @param uploadFilePaths：需要上传的文件路径，数组
     */
    public String uploadFile(String actionUrl, String[] uploadFilePaths) {
        FutureTask<String> future = new FutureTask<>(new Callable<String>() {
            @Override
            public String call() {

                String end = "\r\n";
                String twoHyphens = "--";
                String boundary = "abcdefghijk";

                DataOutputStream ds = null;
                InputStream inputStream = null;
                InputStreamReader inputStreamReader = null;
                BufferedReader reader = null;
                StringBuffer resultBuffer = new StringBuffer();
                String tempLine = null;

                try {
                    // 统一资源
                    URL url = new URL(actionUrl);
                    // 连接类的父类，抽象类
                    URLConnection urlConnection = url.openConnection();
                    // http的连接类
                    HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;

                    // 设置是否从httpUrlConnection读入，默认情况下是true;
                    httpURLConnection.setDoInput(true);
                    // 设置是否向httpUrlConnection输出
                    httpURLConnection.setDoOutput(true);
                    // Post 请求不能使用缓存
                    httpURLConnection.setUseCaches(false);
                    // 设定请求的方法，默认是GET
                    httpURLConnection.setRequestMethod("POST");
                    // 设置字符编码连接参数
                    httpURLConnection.setRequestProperty("Connection", "Keep-Alive");
                    // 设置字符编码
                    httpURLConnection.setRequestProperty("Charset", "UTF-8");
                    // 设置请求内容类型
                    httpURLConnection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);

                    // 设置DataOutputStream
                    ds = new DataOutputStream(httpURLConnection.getOutputStream());

                    ds.writeBytes(twoHyphens + boundary + end);
                    ds.writeBytes("Content-Disposition: form-data; name=\"accessToken\"");
                    ds.writeBytes(end);
                    ds.writeBytes("Content-Length:8");
                    ds.writeBytes(end);
                    ds.writeBytes(end);
                    ds.writeBytes("dengdeng");
                    ds.writeBytes(end);

                    for (int i = 0; i < uploadFilePaths.length; i++) {
                        String uploadFile = uploadFilePaths[i];
                        String filename = uploadFile.substring(uploadFile.lastIndexOf("//") + 1);
                        ds.writeBytes(twoHyphens + boundary + end);
                        ds.writeBytes("Content-Disposition: form-data; " + "name=\"file" + i + "\";filename=\"" + filename + "\"" + end);
                        ds.writeBytes(end);
                        FileInputStream fStream = new FileInputStream(uploadFile);
                        int bufferSize = 1024;
                        byte[] buffer = new byte[bufferSize];
                        int length = -1;
                        while ((length = fStream.read(buffer)) != -1) {
                            ds.write(buffer, 0, length);
                        }
                        ds.writeBytes(end);
                        /* close streams */
                        fStream.close();
                    }
                    ds.writeBytes(twoHyphens + boundary + twoHyphens + end);
                    /* close streams */
                    ds.flush();
                    Log.e("----------", twoHyphens + boundary + end);
                    if (httpURLConnection.getResponseCode() >= 300) {
                        throw new Exception(
                                "HTTP Request is not success, Response code is " + httpURLConnection.getResponseCode() + ",message:" + httpURLConnection.getResponseMessage());
                    }
//            Log.e("response code",httpURLConnection.getResponseMessage()+"---"+httpURLConnection.getResponseCode());
                    if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                        inputStream = httpURLConnection.getInputStream();
                        inputStreamReader = new InputStreamReader(inputStream);
                        reader = new BufferedReader(inputStreamReader);
                        tempLine = null;
                        resultBuffer = new StringBuffer();
                        while ((tempLine = reader.readLine()) != null) {
                            resultBuffer.append(tempLine);
                            resultBuffer.append("\n");
                        }
                    }
                    return resultBuffer.toString();
                } catch (Exception e) {
                    e.printStackTrace();
                    return "";
                } finally {
                    if (ds != null) {
                        try {
                            ds.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (reader != null) {
                        try {
                            reader.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (inputStreamReader != null) {
                        try {
                            inputStreamReader.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (inputStream != null) {
                        try {
                            inputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
        executorService.submit(future);
        String s = "";
        try {
            s = future.get();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return s;
    }
}
